home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume11 / menu_mh / part01 next >
Encoding:
Text File  |  1990-03-10  |  26.2 KB  |  1,176 lines

  1. Newsgroups: comp.sources.misc
  2. subject: v11i024: another menu prog
  3. From: mike@milhow2.UUCP (Mike Howard)
  4. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  5.  
  6. Posting-number: Volume 11, Issue 24
  7. Submitted-by: mike@milhow2.UUCP (Mike Howard)
  8. Archive-name: menu_mh/part01
  9.  
  10.   dumb_menu - executes a simple minded menu
  11.  
  12.   Theory of operation: The program reads and parses a menu
  13.   definition file and then loops until the user quits.  Menus
  14.   are not pretty - simply numbered options with Q for quit to
  15.   exit.
  16.  
  17.   The menu definition file consists of a title statement
  18.   followed by zero or more options followed by one or item
  19.   definitions.
  20.  
  21.  
  22.        title { this is a Title }
  23.  
  24.        bold clear always-show
  25.  
  26.        item { this is a prompt } { echo "$FOO $BAR" }
  27.        parm "FOO" { prompt for FOO }
  28.        parm "BAR" { prompt for BAR }
  29.        ;
  30.  
  31. Mike Howard
  32. how@milhow1.uunet.uu.net
  33.  
  34. ---------------------cut here --------------------------------
  35. #! /bin/sh
  36. # This is a shell archive.  Remove anything before this line, then unpack
  37. # it by saving it into a file and typing "sh file".  To overwrite existing
  38. # files, type "sh file -c".  You can also feed this as standard input via
  39. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  40. # will see the following message at the end:
  41. #        "End of archive 1 (of 1)."
  42. # Contents:  MANIFEST Makefile README directory dumb_menu.1 dumb_menu.l
  43. #   dumb_menu.y menu.def sub.menu
  44. # Wrapped by mike@milhow2 on Thu Mar  8 16:00:36 1990
  45. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  46. if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  47.   echo shar: Will not clobber existing file \"'MANIFEST'\"
  48. else
  49. echo shar: Extracting \"'MANIFEST'\" \(393 characters\)
  50. sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
  51. X   File Name        Archive #    Description
  52. X-----------------------------------------------------------
  53. X MANIFEST                   1    This shipping list
  54. X Makefile                   1    
  55. X README                     1    
  56. X directory                  1    
  57. X dumb_menu.1                1    
  58. X dumb_menu.l                1    
  59. X dumb_menu.y                1    
  60. X menu.def                   1    
  61. X sub.menu                   1    
  62. END_OF_FILE
  63. if test 393 -ne `wc -c <'MANIFEST'`; then
  64.     echo shar: \"'MANIFEST'\" unpacked with wrong size!
  65. fi
  66. # end of 'MANIFEST'
  67. fi
  68. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  69.   echo shar: Will not clobber existing file \"'Makefile'\"
  70. else
  71. echo shar: Extracting \"'Makefile'\" \(939 characters\)
  72. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  73. X#    CFLAGS    =    -g -DFLEX_DEBUG
  74. X#    CFLAGS    =    -g
  75. X#    CFLAGS    =    -g -DYYDEBUG
  76. XCFLAGS    =    -O -DTERMIO -DTERMCAP
  77. XLDFLAGS    =    -ly -ltermcap
  78. X
  79. X# C source files
  80. X# Yacc source files
  81. XYSRC    =    dumb_menu.y
  82. XYCCC    =    $(YSRC:.y=.c)
  83. XYOBJ    =    $(YSRC:.y=.o)
  84. X
  85. XLSRC    =    dumb_menu.l
  86. XLEX    =    flex
  87. XLFLAGS    =
  88. X
  89. Xdumb_menu :  $(YCCC) lex.yy.c
  90. X    $(CC) $(CFLAGS) $(YCCC) $(LDFLAGS) -o dumb_menu
  91. X
  92. Xdumb_menu.0s :  dumb_menu.c lex.yy.c
  93. X    $(CC) $(CFLAGS) -M0s dumb_menu.c $(LDFLAGS) -o dumb_menu.0s
  94. X
  95. Xlex.yy.c : dumb_menu.l
  96. X    $(LEX) $(LFLAGS) dumb_menu.l
  97. X
  98. Xprt : $(YSRC) $(LSRC)
  99. X    for x in $? ; do \
  100. X    pr -f -l60 -e8 -o2 $$x | lp -dlaser ;\
  101. X    done
  102. X    touch prt
  103. X
  104. Xtar :
  105. X    format /dev/rfd096ds9
  106. X    tar cvf /dev/fd096ds9 $(YSRC) $(LSRC) *.1 Makefile s.* *.doc menu.def \
  107. X        *.menu dumb_menu dumb_menu.0s
  108. X
  109. Xclean :
  110. X    rm -f $(OBJS) $(YCCC) lex.yy.c
  111. X
  112. Xkit : $(YSRC) $(LSRC) dumb_menu.1 Makefile menu.def sub.menu directory
  113. X    makekit -m $(YSRC) $(LSRC) dumb_menu.1 Makefile menu.def sub.menu \
  114. X        directory README
  115. X    touch kit
  116. END_OF_FILE
  117. if test 939 -ne `wc -c <'Makefile'`; then
  118.     echo shar: \"'Makefile'\" unpacked with wrong size!
  119. fi
  120. # end of 'Makefile'
  121. fi
  122. if test -f 'README' -a "${1}" != "-c" ; then 
  123.   echo shar: Will not clobber existing file \"'README'\"
  124. else
  125. echo shar: Extracting \"'README'\" \(610 characters\)
  126. sed "s/^X//" >'README' <<'END_OF_FILE'
  127. X  dumb_menu - executes a simple minded menu
  128. X
  129. X  Theory of operation: The program reads and parses a menu
  130. X  definition file and then loops until the user quits.  Menus
  131. X  are not pretty - simply numbered options with Q for quit to
  132. X  exit.
  133. X
  134. X  The menu definition file consists of a title statement
  135. X  followed by zero or more options followed by one or item
  136. X  definitions.
  137. X
  138. X
  139. X       title { this is a Title }
  140. X
  141. X       bold clear always-show
  142. X
  143. X       item { this is a prompt } { echo "$FOO $BAR" }
  144. X       parm "FOO" { prompt for FOO }
  145. X       parm "BAR" { prompt for BAR }
  146. X       ;
  147. X
  148. XMike Howard
  149. Xhow@milhow1.uunet.uu.net
  150. END_OF_FILE
  151. if test 610 -ne `wc -c <'README'`; then
  152.     echo shar: \"'README'\" unpacked with wrong size!
  153. fi
  154. # end of 'README'
  155. fi
  156. if test -f 'directory' -a "${1}" != "-c" ; then 
  157.   echo shar: Will not clobber existing file \"'directory'\"
  158. else
  159. echo shar: Extracting \"'directory'\" \(99 characters\)
  160. sed "s/^X//" >'directory' <<'END_OF_FILE'
  161. Xdumb_menu.1:The Manual Page
  162. Xdumb_menu.l:The Lexical Analyzer
  163. Xdumb_menu.y:The parser & Main Program
  164. END_OF_FILE
  165. if test 99 -ne `wc -c <'directory'`; then
  166.     echo shar: \"'directory'\" unpacked with wrong size!
  167. fi
  168. # end of 'directory'
  169. fi
  170. if test -f 'dumb_menu.1' -a "${1}" != "-c" ; then 
  171.   echo shar: Will not clobber existing file \"'dumb_menu.1'\"
  172. else
  173. echo shar: Extracting \"'dumb_menu.1'\" \(3436 characters\)
  174. sed "s/^X//" >'dumb_menu.1' <<'END_OF_FILE'
  175. X.    \"    -*- nroff -*-
  176. X.    \"    @(#)dumb_menu.1    1.2 90/03/08
  177. X.DA March 8, 1990
  178. X.TH DUMB_MENU 1 "local"
  179. X.SH NAME
  180. Xdumb_menu \- executes a simple minded menu
  181. X.SH SYNOPSIS
  182. X.B dumb_menu
  183. X[ -h | options ]
  184. X.SH DESCRIPTION
  185. X.PP
  186. X.B -m path
  187. Xsets the path to the menu definition file.  Default is
  188. X.I ./menu.def.
  189. X.PP
  190. X.B -s path
  191. Xsets path for the shell which will execute the selected menu command.
  192. XDefault is
  193. X.I /bin/sh
  194. X.PP
  195. X.B -c path
  196. Xsets the path to
  197. X.B cat
  198. Xwhich is used to display the command selected in debug mode.
  199. X.PP
  200. X.B -D
  201. Xincrements debug mode.  There are two modes - one simply lists the
  202. Xfile and cat's the selected options rather than executing them.
  203. XThe other displays the statements which are discovered during the
  204. Xparsing phase.
  205. X.B -v
  206. Ximplements a quasi-verbose mode.  This is done by prepending the
  207. Xcommand
  208. X.I set -x
  209. Xto the front of the shell script prior to feeding it to a shell.
  210. X.PP
  211. XTheory of operation: The program reads and parses a menu definition
  212. Xfile and then loops until the user quits.  Menus are not pretty -
  213. Xsimply numbered options with Q for quit to exit.
  214. X.PP
  215. XThe menu definition file consists of a 
  216. X.B title
  217. Xstatement followed by zero or more
  218. X.B options
  219. Xfollowed by one or
  220. X.B item
  221. Xdefinitions.
  222. X.PP
  223. XThe
  224. X.B title
  225. Xstatement contains the menu title enclosed in braces ({ foo }).
  226. X.IP
  227. Xtitle { some text }
  228. X.PP
  229. XTitles the menu with the title ``some text''.
  230. X.PP
  231. XLegal menu options are
  232. X.B clear, bold,
  233. Xand
  234. X.B always-show.
  235. X.HP
  236. X.B clear
  237. Xcauses the screen to be cleared prior to displaying the menu.  It also
  238. Xcauses a
  239. X.I [ Hit Return to Continue ]
  240. Xmessage to be displayed upon the completion of processing a selection.
  241. X.HP
  242. X.B bold
  243. Xcauses the menu title to be displayed in
  244. X.I standout mode,
  245. Xif the terminal type is defined and supports it.
  246. X.HP
  247. X.B always-show
  248. Xcauses the menu selections to always be re-displayed after a menu
  249. Xselection is completed.  Otherwise, only the title and the ``Q) to
  250. XQuit, ? for menu'' message is displayed.
  251. X.PP
  252. XItem definitions begin with the key word
  253. X.B item
  254. Xand are terminated by a semi-colon (;).
  255. XThe word
  256. X.B item 
  257. Xis followed by the prompt string enclosed in braces, which is
  258. Xfollowed by the shell script to run, enclosed in braces.
  259. XThe shell script is followed by zero or more parameter definitions.
  260. X.PP
  261. XParameter definitions begin with the key word
  262. X.B parm,
  263. Xare followed by the parameter identifier enclosed in double
  264. Xquote marks ("), which is
  265. Xfollowed by the prompt for the parameter enclosed in braces.
  266. XParameter identifiers may only contain alphanumeric
  267. Xcharacters  (A-Z,a-z, 0-9, and _), as a crude form of error checking.
  268. X.PP
  269. X.B NOTE:
  270. Xtext bounded by braces (\ {\ }\ ) in
  271. X.B title, item,
  272. Xand
  273. X.B parm
  274. Xstatements may contain any character except nulls ('\\0') and
  275. Xnon-escaped back-slashes (\\) and right braces (}).  Nulls are
  276. Xillegal, because the lexical analyzer won't deal with them.
  277. XSingle back-slashes and right braces are written as \\\\ and \\},
  278. Xrespectively.  Other back-slash escape sequences needed in scripts for
  279. Xother reasons do not need to be escaped \- i.e. echo "\\nfoo" in a
  280. Xshell script does
  281. X.I not
  282. Xneed to be written echo "\\\\nfoo".
  283. X.IP
  284. Xtitle { this is a Title }
  285. X.IP
  286. Xbold clear always-show
  287. X.IP
  288. Xitem { this is a prompt } { echo "$FOO $BAR" }
  289. X.IP
  290. Xparm "FOO" { prompt for FOO }
  291. X.IP
  292. Xparm "BAR" { prompt for BAR }
  293. X.IP
  294. X;
  295. X.SH DIAGNOSTICS
  296. X.PP
  297. XThe diagnostics during the parse of the menu definition are all but
  298. Xnon-existent.
  299. X.SH BUGS
  300. X.PP
  301. XHas no provision for menus which exceed one screen in size.
  302. END_OF_FILE
  303. if test 3436 -ne `wc -c <'dumb_menu.1'`; then
  304.     echo shar: \"'dumb_menu.1'\" unpacked with wrong size!
  305. fi
  306. # end of 'dumb_menu.1'
  307. fi
  308. if test -f 'dumb_menu.l' -a "${1}" != "-c" ; then 
  309.   echo shar: Will not clobber existing file \"'dumb_menu.l'\"
  310. else
  311. echo shar: Extracting \"'dumb_menu.l'\" \(2584 characters\)
  312. sed "s/^X//" >'dumb_menu.l' <<'END_OF_FILE'
  313. X    /* @(#)dumb_menu.l    1.2 90/03/08 */
  314. X    /* copyrite (c) Miller/Howard Investments, 1990 */
  315. X
  316. X%{
  317. X/* this thing is designed to use flex, not lex.  If you don't have
  318. X   it, then you'll have to re-write the lexical analyser */
  319. X
  320. X#include <ctype.h>
  321. X
  322. X  char *saved_text;
  323. X%}
  324. X
  325. X    /* global definitions */
  326. X
  327. X%x P_STATE T_STATE
  328. X
  329. X%%
  330. X
  331. Xitem    return ITEM;
  332. Xparm    return PARM;
  333. Xtitle    return TITLE;
  334. Xclear    return CLEAR;
  335. Xbold    return BOLD;
  336. X"always-show"    return ALWAYS_SHOW;
  337. X"{"    { BEGIN T_STATE ; }
  338. X\"    { BEGIN P_STATE; }
  339. X";"    return ';';
  340. X[ \t]+    ;
  341. X\n    line_number++;
  342. X.    return ERROR;
  343. X
  344. X<T_STATE>"\\}"    add_text("}");
  345. X<T_STATE>"}"    {
  346. X    strip_white_space();
  347. X      yylval.txt = saved_text;
  348. X    saved_text = (char *)0;
  349. X    BEGIN 0;
  350. X    return TEXT; }
  351. X<T_STATE>"\\\n"    {
  352. X    line_number++;
  353. X    add_text(yytext);
  354. X    }
  355. X<T_STATE>\\.    add_text(yytext);
  356. X<T_STATE>[^\\}\n]+    add_text(yytext);
  357. X<T_STATE>"\n"    {
  358. X    line_number++;
  359. X    add_text("\n");
  360. X    }
  361. X
  362. X<P_STATE>[A-Za-z0-9_]+    add_text(yytext);
  363. X<P_STATE>\"    {
  364. X    if (saved_text) {
  365. X      strip_white_space();
  366. X      yylval.txt = saved_text;
  367. X      saved_text = (char *)0;
  368. X      BEGIN 0;
  369. X      return PARM_NAME;
  370. X    }
  371. X    fprintf(stderr, "lex error\n");
  372. X    lex_errors++;
  373. X    return ERROR;
  374. X    }
  375. X%%
  376. X
  377. X/* c program text */
  378. X
  379. X#define INIT_SIZE    256
  380. X#define INC_SIZE    64
  381. X
  382. Xadd_text(s)
  383. Xchar *s;
  384. X{
  385. X  static int saved_length;
  386. X  static int room_left;
  387. X  int len = strlen(s);
  388. X  static int saved_size;
  389. X
  390. X  if (!saved_text) {
  391. X    memset(saved_text = malloc(INIT_SIZE), '\0', INIT_SIZE);
  392. X    room_left = INIT_SIZE;
  393. X    saved_size = INIT_SIZE;
  394. X    saved_length = 0;
  395. X  }
  396. X
  397. X  len++;            /* inc len to account for terminating null */
  398. X  while (len >= room_left) {
  399. X    saved_text = realloc(saved_text, saved_size += INC_SIZE);
  400. X    room_left += INC_SIZE;
  401. X  }
  402. X
  403. X  memcpy(saved_text + saved_length, s, len);
  404. X  /* the trailing null will be overwritten next time
  405. X     so it doesn't count in computing room left */
  406. X  room_left -= --len;
  407. X  saved_length += len;
  408. X}
  409. X
  410. Xstrip_white_space()
  411. X{
  412. X  char *cp;
  413. X  char *sp;
  414. X
  415. X  if (!saved_text)
  416. X    return;
  417. X
  418. X  for (cp = saved_text + strlen(saved_text) - 1;cp > saved_text;cp--) {
  419. X    if (!isspace(*cp))
  420. X      break;
  421. X  }
  422. X  *++cp = '\0';
  423. X
  424. X  for (cp=saved_text;*cp && isspace(*cp);cp++)
  425. X    ;
  426. X
  427. X  /* is it all white? */
  428. X  if (!*cp && cp > saved_text) {
  429. X    saved_text = realloc(saved_text, 1);
  430. X    *saved_text = '\0';
  431. X    return;
  432. X  }
  433. X
  434. X  /* is there any leading white space? */
  435. X  if (cp > saved_text) {
  436. X    char *tmp;
  437. X    int len;
  438. X
  439. X    tmp = malloc(len = strlen(cp) + 1);
  440. X    memcpy(tmp, cp, len);
  441. X    free(saved_text);
  442. X    saved_text = tmp;
  443. X
  444. X    return;
  445. X  }
  446. X
  447. X  saved_text = realloc(saved_text, strlen(saved_text) + 1);
  448. X}
  449. X
  450. X#ifdef yywrap
  451. X#undef yywrap
  452. X#endif
  453. END_OF_FILE
  454. if test 2584 -ne `wc -c <'dumb_menu.l'`; then
  455.     echo shar: \"'dumb_menu.l'\" unpacked with wrong size!
  456. fi
  457. # end of 'dumb_menu.l'
  458. fi
  459. if test -f 'dumb_menu.y' -a "${1}" != "-c" ; then 
  460.   echo shar: Will not clobber existing file \"'dumb_menu.y'\"
  461. else
  462. echo shar: Extracting \"'dumb_menu.y'\" \(11883 characters\)
  463. sed "s/^X//" >'dumb_menu.y' <<'END_OF_FILE'
  464. X%{
  465. X/* @(#)dumb_menu.y    1.3 90/03/08 */
  466. X
  467. Xstatic char *cpy_str =
  468. X  "Copyright (c), Mike Howard, 1990, all rights reserved";
  469. X
  470. X/* Conditions of use:
  471. X
  472. X   This software is not for sale and is not to be sold by or
  473. X   to anyone.
  474. X
  475. X   You may use this software and may distribute it to anyone
  476. X   you wish to provided you distribute the entire distribution
  477. X   package w/o any deletions (i.e. include all the source code).
  478. X
  479. X   I do not warrent this software to do anything at all and
  480. X   am not responsible for anything which happens as a result of
  481. X   its use.
  482. X*/
  483. X
  484. X#include <stdio.h>
  485. X#include <fcntl.h>
  486. X#include <string.h>
  487. X#include <signal.h>
  488. X#include <setjmp.h>
  489. X
  490. Xstruct parm {
  491. X  struct parm *next;
  492. X  char *prompt;
  493. X  char *identifier;
  494. X  char *value;
  495. X};
  496. X
  497. Xstruct item {
  498. X  struct item *next;
  499. X  char *prompt;
  500. X  char *command;
  501. X  struct parm *parms;
  502. X};
  503. X
  504. Xstruct item *menu_head;
  505. Xstruct item *menu_tail;
  506. X
  507. Xint max_item;
  508. X
  509. Xstruct parm *parm_list;
  510. X
  511. Xchar *menu_title;
  512. X
  513. Xchar *malloc();
  514. Xchar *realloc();
  515. X
  516. Xint lex_errors;
  517. Xint yacc_errors;
  518. Xint line_number;
  519. X
  520. X/* flags */
  521. Xint clear_flag;
  522. Xint bold_flag;
  523. Xint always_display_menu_flag;
  524. X
  525. X/* Menus begin with a title definition
  526. X   title { text for the title }
  527. X
  528. X   This is followed by one or more menu-item definitions of the form:
  529. X
  530. X   item { prompt } { shell command }
  531. X   parm "name" { prompt }
  532. X   parm "name" { prompt }
  533. X   ;
  534. X
  535. X   the crud in between braces may contain any character, including
  536. X   escapped braces and back-slash (\).
  537. X   The crud in between the double quotes may ONLY contain letters, digits,
  538. X   and underscores;
  539. X
  540. X   Sub-menus are formed by running dumb_menu as the shell process, pointed
  541. X   to an appropriate sub-menu definition file.
  542. X
  543. X   There is no provision for menus which require more than one screen 
  544. X   to display.
  545. X*/
  546. X
  547. X#define DEBUG0(fmt)    if(debug_mode>1)printf(fmt);
  548. X#define DEBUG1(fmt,aa)    if(debug_mode>1)printf(fmt,aa);
  549. X#define DEBUG2(fmt,aa,bb)    if(debug_mode>1)printf(fmt,aa,bb);
  550. X#define DEBUG3(fmt,aa,bb,cc)    if(debug_mode>1)printf(fmt,aa,bb,cc);
  551. X
  552. X%}
  553. X
  554. X%union {
  555. X  int ival;
  556. X  char *txt;
  557. X  char chr;
  558. X  double dbl;
  559. X  struct item *itm;
  560. X  struct parm *prm;
  561. X}
  562. X
  563. X%token <ival> NUMBER
  564. X%token <dbl> FLOAT
  565. X%token <txt> TEXT PARM_NAME
  566. X%token PARM ITEM TITLE ERROR
  567. X%token CLEAR BOLD ALWAYS_SHOW
  568. X
  569. X%type <itm> menu item
  570. X%type <prm> parm
  571. X
  572. X%%
  573. X
  574. Xmenu : title menu_flags item
  575. X    {
  576. X      menu_head =
  577. X        menu_tail = $3;
  578. X      DEBUG1("Initial Menu Item:\n %s\n", $3->prompt);
  579. X    }
  580. X    | menu item
  581. X    {
  582. X      menu_tail->next = $2;
  583. X      menu_tail = $2;
  584. X      DEBUG1("Additional Menu Item:\n %s\n", $2->prompt);
  585. X    }
  586. X    ;
  587. X
  588. Xtitle : TITLE TEXT
  589. X    {
  590. X      menu_title = $2;
  591. X      DEBUG1("menu title '%s'\n", $2);
  592. X    }
  593. X    ;
  594. X
  595. Xmenu_flags :
  596. X    | menu_flags menu_flag
  597. X    ;
  598. X
  599. Xmenu_flag : CLEAR
  600. X    {
  601. X      clear_flag++;
  602. X    }
  603. X    | BOLD
  604. X    {
  605. X      bold_flag++;
  606. X    }
  607. X    | ALWAYS_SHOW
  608. X    {
  609. X      always_display_menu_flag++;
  610. X    }
  611. X    ;
  612. X
  613. Xitem : ITEM  TEXT  TEXT  parms ';'
  614. X    {
  615. X      $$ = make_new_item($2, $3, parm_list);
  616. X      parm_list = (struct parm *)0;
  617. X    }
  618. X    ;
  619. X
  620. Xparms : /* empty */
  621. X    | parms parm
  622. X    ;
  623. X
  624. Xparm : PARM PARM_NAME TEXT
  625. X    {
  626. X      $$ = make_new_parm($2, $3);
  627. X      $$->next = parm_list;
  628. X      parm_list = $$;
  629. X      DEBUG2("parm: %s\n'%s'\n", $2, $3);
  630. X    }
  631. X    ;
  632. X
  633. X%%
  634. X
  635. Xchar *use_msg = "usage: %s [-h | option(s) ]\n";
  636. X
  637. Xextern char *optarg;
  638. Xextern int optind, opterr;
  639. Xint tty_in;
  640. XFILE *tty_file;
  641. Xint argcc;
  642. Xchar **argvv;
  643. Xchar *progname;
  644. Xchar *in_fname = "stdin";
  645. Xchar *menu_fname = "./menu.def";
  646. Xchar *shell_path = "/bin/sh";
  647. Xchar *cat_path = "/bin/cat";
  648. Xchar *cmd_path;
  649. Xchar *cmd_name;
  650. X
  651. Xstruct item *selected_item;
  652. Xstruct parm *selected_parms;
  653. XFILE *tmp_file;
  654. Xchar *tmp_fname;
  655. X
  656. Xint verbose;
  657. Xint debug_mode;
  658. X
  659. Xchar *hlp[] = {
  660. X"Option     Function",
  661. X"-m file    set menu-definition file name to 'file' (menu.def)",
  662. X"-s path    path to shell to execute scripts",
  663. X"-c path    path to 'cat' for simple debug mode",
  664. X"-v         make command execution verbose (via set -xv)",
  665. X"-D         increment debug mode",
  666. X(char *)0};
  667. X
  668. Xint display_menu_flag = 1;
  669. Xjmp_buf env;
  670. X#define SIGS_FOR_JMP   1
  671. X#define SIGS_FOR_CHILD 2
  672. X
  673. Xmain(argc, argv)
  674. Xint argc;
  675. Xchar **argv;
  676. X{
  677. X  int item_idx;
  678. X
  679. X  init(argc, argv);
  680. X
  681. X  if (yyparse())
  682. X    fatal("Parse Error");
  683. X
  684. X  if (lex_errors || yacc_errors)
  685. X    fatal("corrupt menu definition");
  686. X
  687. X  if (debug_mode) {
  688. X    item_idx = 1;
  689. X    for (selected_item=menu_head;selected_item;
  690. X     selected_item = selected_item->next) {
  691. X      printf("%2d. %s\n", item_idx++, selected_item->prompt);
  692. X      printf("%s\n", selected_item->command);
  693. X      for (selected_parms=selected_item->parms;selected_parms;
  694. X       selected_parms = selected_parms->next)
  695. X    printf("%s: '%s'\n", selected_parms->prompt,
  696. X           selected_parms->identifier);
  697. X    }
  698. X  }
  699. X
  700. X  init_terminal();
  701. X
  702. X  do_menu();
  703. X}
  704. X
  705. Xinit(argc, argv)
  706. Xint argc;
  707. Xchar **argv;
  708. X{
  709. X  int i;
  710. X  int c;
  711. X  extern char *optarg;
  712. X  extern int optind, opterr;
  713. X
  714. X  while ((c = getopt(argc, argv, "hcsm:vD")) != EOF) {
  715. X    switch (c) {
  716. X    case 'h':
  717. X      for (i=0;hlp[i];i++)
  718. X    printf("%s\n", hlp[i]);
  719. X      fatal((char *)0);
  720. X    case 's':
  721. X      shell_path = optarg;
  722. X      break;
  723. X    case 'c':
  724. X      cat_path = optarg;
  725. X      break;
  726. X    case 'm':
  727. X      menu_fname = optarg;
  728. X      break;
  729. X    case 'v':
  730. X      verbose++;
  731. X      break;
  732. X    case 'D':
  733. X      debug_mode++;
  734. X      break;
  735. X    case '?':
  736. X      fatal((char *)0);
  737. X    }
  738. X  }
  739. X
  740. X  argcc = argc;
  741. X  argvv = argv;
  742. X  progname = argv[0];
  743. X  if (strcmp(menu_fname, "-")) {
  744. X    close(0);
  745. X
  746. X    if (open(menu_fname, O_RDONLY) < 0) {
  747. X      char buf[80];
  748. X
  749. X      sprintf(buf, "cannot open menu definition: %s", menu_fname);
  750. X      fatal(buf);
  751. X    }
  752. X  }
  753. X
  754. X  if ((tty_in = open("/dev/tty", O_RDONLY)) < 0)
  755. X    fatal("cannot open tty - must be run interactively");
  756. X  tty_file = fdopen(tty_in, "r");
  757. X
  758. X  cmd_path = debug_mode ? cat_path : shell_path;
  759. X  if (cmd_name = strrchr(cmd_path, '/'))
  760. X    cmd_name++;
  761. X  else
  762. X    cmd_name = cmd_path;
  763. X}
  764. X
  765. Xstruct parm *make_new_parm(identifier, prompt)
  766. Xchar *identifier;
  767. Xchar *prompt;
  768. X{
  769. X  struct parm *parm_ptr = (struct parm *)malloc(sizeof(struct parm));
  770. X
  771. X  if (!parm_ptr)
  772. X    fatal("malloc() error");
  773. X
  774. X  parm_ptr->next = (struct parm *)0;
  775. X  parm_ptr->prompt = prompt;
  776. X  parm_ptr->identifier = identifier;
  777. X  parm_ptr->value = "";
  778. X
  779. X  return parm_ptr;
  780. X}
  781. X
  782. Xstruct item *make_new_item(prompt, command, parms)
  783. Xchar *prompt;
  784. Xchar *command;
  785. Xstruct parm *parms;
  786. X{
  787. X  struct item *item_ptr = (struct item *)malloc(sizeof(struct item));
  788. X
  789. X  if (!item_ptr)
  790. X    fatal("malloc() error");
  791. X
  792. X  item_ptr->next = (struct item *)0;
  793. X  item_ptr->prompt = prompt;
  794. X  item_ptr->command = command;
  795. X  item_ptr->parms = parms;
  796. X
  797. X  return item_ptr;
  798. X}
  799. X
  800. Xchar tty_bp[1024];
  801. Xchar tty_caps[1024];
  802. Xchar *term_cm;
  803. Xchar *term_so;
  804. Xchar *term_se;
  805. Xint term_sg;
  806. Xchar *term_cl;
  807. Xint term_lines;
  808. Xchar PC;
  809. Xchar *BC;
  810. Xchar *UP;
  811. Xshort ospeed;
  812. X
  813. Xint outc(c)
  814. Xint c;
  815. X{
  816. X  putc(c, stdout);
  817. X}
  818. X
  819. Xinit_terminal()
  820. X{
  821. X  char *getenv();
  822. X  char *tty_type = getenv("TERM");
  823. X  char *cp = tty_caps;
  824. X  char *tgetstr();
  825. X
  826. X  if (!tty_type || tgetent(tty_bp, tty_type) <= 0) {
  827. X    clear_flag =
  828. X      bold_flag = 0;
  829. X    return;
  830. X  }
  831. X
  832. X  PC = *tgetstr("pc", &cp);
  833. X  BC = tgetstr("bc", &cp);
  834. X  UP = tgetstr("up", &cp);
  835. X#ifdef TERMIO
  836. X  {
  837. X#include <sys/termio.h>
  838. X
  839. X    struct termio termio;
  840. X
  841. X    ioctl(0, TCGETA, &termio);
  842. X    ospeed = termio.c_cflag & CBAUD;
  843. X  }
  844. X#undef ECHO /* conflicts with lex code */
  845. X#endif /* TERMIO */
  846. X  term_cm = tgetstr("cm", &cp);
  847. X  if (bold_flag) {
  848. X    term_so = tgetstr("so", &cp);
  849. X    term_se = tgetstr("se", &cp);
  850. X    term_sg = tgetnum("sg");
  851. X    if (!term_so)
  852. X      bold_flag = 0;
  853. X  }
  854. X  if (clear_flag) {
  855. X    term_cl = tgetstr("cl", &cp);
  856. X    term_lines = tgetnum("li");
  857. X    if (!term_cl)
  858. X      clear_flag = 0;
  859. X  }
  860. X}
  861. X
  862. Xdo_menu()
  863. X{
  864. X  int item_idx;
  865. X  int pid;
  866. X
  867. X  while (1) {
  868. X  again:
  869. X    setjmp(env);
  870. X    set_signals(SIGS_FOR_JMP);
  871. X
  872. X    while (1) {
  873. X      char buf[80];
  874. X      char *cp;
  875. X      int rsp;
  876. X
  877. X      display_menu();
  878. X      fgets(buf, 80, tty_file);
  879. X      if (cp = strchr(buf, '\n'))
  880. X    *cp = '\0';
  881. X
  882. X      if (strchr(buf, 'Q') || strchr(buf, 'q'))
  883. X    exit(0);
  884. X
  885. X      if (strchr(buf, '?')) {
  886. X    display_menu_flag = 1;
  887. X    goto again;
  888. X      }
  889. X
  890. X      if (sscanf(buf, "%d", &item_idx) != 1) {
  891. X    printf("'%s' is not a legal response\n", buf);
  892. X    goto again;
  893. X      }
  894. X
  895. X      if (--item_idx < 0 || item_idx >= max_item) {
  896. X    printf("'%s' is not a legal response\n", buf);
  897. X    goto again;
  898. X      }
  899. X      else
  900. X    break;
  901. X    }
  902. X
  903. X    selected_item = menu_head;
  904. X    while (item_idx-- > 0)
  905. X      selected_item = selected_item->next;
  906. X
  907. X    selected_parms = selected_item->parms;
  908. X
  909. X    while (selected_parms) {
  910. X      char buf[256];
  911. X      char *cp;
  912. X
  913. X      printf("%s: ", selected_parms->prompt);
  914. X      fflush(stdout);
  915. X      fgets(buf, 255, tty_file);
  916. X      if (cp = strchr(buf, '\n'))
  917. X    *cp = '\0';
  918. X
  919. X      strcpy(selected_parms->value = malloc(strlen(buf) + 1), buf);
  920. X      selected_parms = selected_parms->next;
  921. X    }
  922. X
  923. X    tmp_fname = tmpnam((char *)0);
  924. X    set_signals(SIGS_FOR_CHILD);
  925. X    if ((tmp_file = fopen(tmp_fname, "w")) == NULL)
  926. X      fatal("cannot create temp file for shell");
  927. X    if (verbose)
  928. X      fprintf(tmp_file, "set -xv\n");
  929. X    for (selected_parms=selected_item->parms;selected_parms;
  930. X     selected_parms=selected_parms->next) {
  931. X      fprintf(tmp_file, "%s=\"%s\"\n", selected_parms->identifier,
  932. X          selected_parms->value);
  933. X      free(selected_parms->value);
  934. X      selected_parms->value = "";
  935. X    }
  936. X    fprintf(tmp_file, "%s\n", selected_item->command);
  937. X    fclose(tmp_file);
  938. X
  939. X    if ( !(pid = fork()) ) {
  940. X      /* reset signals so that DEL,... work correctly */
  941. X      reset_signals();
  942. X      close(0);
  943. X      dup(tty_in);
  944. X      close(tty_in);
  945. X      fclose(tty_file);
  946. X      execl(cmd_path, cmd_name, tmp_fname, (char *)0);
  947. X      fatal("exec of command failed");
  948. X    }
  949. X
  950. X    wait_for_child(pid);
  951. X    unlink(tmp_fname);
  952. X    tmp_fname = (char *)0;
  953. X    if (clear_flag) {
  954. X      char buf[80];
  955. X
  956. X      printf("[Press Return to Continue]");
  957. X      fflush(stdout);
  958. X      fgets(buf, 80, tty_file);
  959. X    }
  960. X  }
  961. X  reset_signals();
  962. X}
  963. X
  964. Xdisplay_menu()
  965. X{
  966. X  struct item *ptr = menu_head;
  967. X  int i;
  968. X
  969. X  /* if we clear the screen, then do it, otherwise skip a line */
  970. X  if (clear_flag)
  971. X    tputs(term_cl, term_lines, outc);
  972. X  else
  973. X    putc('\n', stdout);
  974. X
  975. X  /* this is not correct for magic cookie tubes - but I don't feel
  976. X     like counting lines in menu_title, maintaining line counts in the
  977. X     case we don't clear-screen-before-displaying, ...
  978. X     So if you have a stupid tube - it is going to flash */
  979. X  if (bold_flag) {
  980. X    tputs(term_so, 1, outc);
  981. X    printf("%s", menu_title);
  982. X    tputs(term_se, 1, outc);
  983. X    putc('\n', stdout);
  984. X  }
  985. X  else
  986. X    printf("%s\n", menu_title);
  987. X
  988. X  if (display_menu_flag) {
  989. X    for (i=0;ptr;i++,ptr = ptr->next)
  990. X      printf("%2d. %s\n", i + 1, ptr->prompt);
  991. X    max_item = i;
  992. X  }
  993. X
  994. X  printf( always_display_menu_flag ? "Q) to End - choice? " :
  995. X     "Q) to End, ?) for Menu - choice? ");
  996. X  fflush(stdout);
  997. X
  998. X  display_menu_flag = always_display_menu_flag;
  999. X}
  1000. X
  1001. X#include "lex.yy.c"
  1002. X
  1003. X
  1004. Xfatal(s)
  1005. Xchar *s;
  1006. X{
  1007. X  extern int errno;
  1008. X  char msg_buf[80];
  1009. X
  1010. X  fprintf(stderr, use_msg, progname);
  1011. X  if (s)
  1012. X    fprintf(stderr, "%s\n", s);
  1013. X
  1014. X  if (errno) {
  1015. X    sprintf(msg_buf, "fatal error '%s': line %d", menu_fname, line_number);
  1016. X    perror(msg_buf);
  1017. X  }
  1018. X  exit(1);
  1019. X}
  1020. X
  1021. Xvoid trapoid(sig)
  1022. Xint sig;
  1023. X{
  1024. X  if (tmp_fname)
  1025. X    unlink(tmp_fname);
  1026. X
  1027. X  exit(sig);
  1028. X}
  1029. X
  1030. Xdo_longjmp(sig)
  1031. Xint sig;
  1032. X{
  1033. X  longjmp(env, 0);
  1034. X}
  1035. X
  1036. Xwait_for_child(pid)
  1037. Xint pid;
  1038. X{
  1039. X  int wait_ret;
  1040. X  int status;
  1041. X  extern int errno;
  1042. X
  1043. X  while ((wait_ret = wait(&status)) != pid) {
  1044. X    /* test to see if child is still there - if not, then return */
  1045. X    if (kill(pid, 0) < 0)
  1046. X      return;
  1047. X  }
  1048. X}
  1049. X
  1050. Xset_signals(flag)
  1051. Xint flag;
  1052. X{
  1053. X  switch (flag) {
  1054. X  case SIGS_FOR_JMP:
  1055. X    signal(SIGHUP, trapoid);
  1056. X    signal(SIGINT, do_longjmp);
  1057. X    signal(SIGQUIT, do_longjmp);
  1058. X    signal(SIGTERM, trapoid);
  1059. X    break;
  1060. X  case SIGS_FOR_CHILD:
  1061. X    signal(SIGHUP, trapoid);
  1062. X    signal(SIGINT, SIG_IGN);
  1063. X    signal(SIGQUIT, SIG_IGN);
  1064. X    signal(SIGTERM, trapoid);
  1065. X    break;
  1066. X  }
  1067. X}
  1068. X
  1069. Xreset_signals()
  1070. X{
  1071. X  signal(SIGHUP, SIG_DFL);
  1072. X  signal(SIGINT, SIG_DFL);
  1073. X  signal(SIGQUIT, SIG_DFL);
  1074. X  signal(SIGTERM, SIG_DFL);
  1075. X  signal(SIGCLD, SIG_DFL);
  1076. X}
  1077. END_OF_FILE
  1078. if test 11883 -ne `wc -c <'dumb_menu.y'`; then
  1079.     echo shar: \"'dumb_menu.y'\" unpacked with wrong size!
  1080. fi
  1081. # end of 'dumb_menu.y'
  1082. fi
  1083. if test -f 'menu.def' -a "${1}" != "-c" ; then 
  1084.   echo shar: Will not clobber existing file \"'menu.def'\"
  1085. else
  1086. echo shar: Extracting \"'menu.def'\" \(576 characters\)
  1087. sed "s/^X//" >'menu.def' <<'END_OF_FILE'
  1088. Xtitle { Test Menu }
  1089. X
  1090. Xclear bold always-show
  1091. X
  1092. Xitem { First Item }
  1093. X{ echo $PARM1 }
  1094. Xparm "PARM1" { Input Parm 1 }
  1095. X;
  1096. X
  1097. Xitem { Second Item }
  1098. X{ echo "This is $PARM and $FOO" }
  1099. Xparm "PARM" { input value for PARM }
  1100. Xparm "FOO" {input value for FOO }
  1101. X;
  1102. X
  1103. Xitem { Submenu }
  1104. X{ awk -F: '
  1105. XBEGIN {
  1106. X  print "title { A dynamically constructed submenu \}"
  1107. X  print "clear bold"
  1108. X\}
  1109. X{
  1110. X  print "item { Browse " $2 " \} { less -cM " $1 " \} ;"
  1111. X\}
  1112. X' directory | dumb_menu -m -
  1113. X}
  1114. X;
  1115. X
  1116. Xitem { Execute a Command }
  1117. X{ $CMD }
  1118. Xparm "CMD" { Command Line }
  1119. X;
  1120. X
  1121. Xitem { Another Submenu }
  1122. X{  dumb_menu -m sub.menu }
  1123. X;
  1124. END_OF_FILE
  1125. if test 576 -ne `wc -c <'menu.def'`; then
  1126.     echo shar: \"'menu.def'\" unpacked with wrong size!
  1127. fi
  1128. # end of 'menu.def'
  1129. fi
  1130. if test -f 'sub.menu' -a "${1}" != "-c" ; then 
  1131.   echo shar: Will not clobber existing file \"'sub.menu'\"
  1132. else
  1133. echo shar: Extracting \"'sub.menu'\" \(215 characters\)
  1134. sed "s/^X//" >'sub.menu' <<'END_OF_FILE'
  1135. Xtitle { A non-descript submenu
  1136. XWith a multi-line
  1137. Xtitle }
  1138. X
  1139. Xitem { Sub-Item 1
  1140. X     long prompt }
  1141. X{ echo "\nSub-Item 1" }
  1142. X;
  1143. X
  1144. Xitem { Sub-Item 2 }
  1145. X{ echo "\nSub-Item 2" }
  1146. X;
  1147. X
  1148. Xitem { Sub-Item 3 }
  1149. X{ echo "\nSub-Item 3" }
  1150. X;
  1151. END_OF_FILE
  1152. if test 215 -ne `wc -c <'sub.menu'`; then
  1153.     echo shar: \"'sub.menu'\" unpacked with wrong size!
  1154. fi
  1155. # end of 'sub.menu'
  1156. fi
  1157. echo shar: End of archive 1 \(of 1\).
  1158. cp /dev/null ark1isdone
  1159. MISSING=""
  1160. for I in 1 ; do
  1161.     if test ! -f ark${I}isdone ; then
  1162.     MISSING="${MISSING} ${I}"
  1163.     fi
  1164. done
  1165. if test "${MISSING}" = "" ; then
  1166.     echo You have the archive.
  1167.     rm -f ark[1-9]isdone
  1168. else
  1169.     echo You still need to unpack the following archives:
  1170.     echo "        " ${MISSING}
  1171. fi
  1172. ##  End of shell archive.
  1173. exit 0
  1174.  
  1175.  
  1176.